#include "reactor.h"

// 因为这些函数只在本文档使用，所以没有必要添加到头文件
static Singleton *m_VariableC = NULL;
void setVariableC();
void set_event(int fd, enum EPOLL_EVENTS events, enum _EPOLL_CTRL ctrl);
int send_cb(int fd);
int recv_cb(int fd);
int accept_cb(int fd);
void* runLoop_reactor(void *arg);
void setListenPortNum(unsigned short beginPort,unsigned short number);//设置监听端口数量
void closeListen();//关闭监听端口
CallbackParser parsercallback_Reactor = NULL;

int Init_server_Reactor(int port)
{
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sockserver;
    memset(&sockserver, 0, sizeof(sockserver));
    sockserver.sin_family = AF_INET;
    sockserver.sin_addr.s_addr = INADDR_ANY;
    sockserver.sin_port = htons(port);
    bind(listenfd, (struct sockaddr *)&sockserver, sizeof(struct sockaddr_in));

    listen(listenfd, 10);
#ifdef PRINTFCMODE
    printf("listenfd：%d\n", listenfd);
#endif
    return listenfd;
}

void setListenPortNum(unsigned short beginPort, unsigned short number)
{
    setVariableC();

    // 注意语句顺序
    m_VariableC->epfd = epoll_create(1);

    for (int i = 0; i < number; i++)
    {
        int listenfd = Init_server_Reactor(beginPort + i);
        m_VariableC->conn_list[listenfd].fd = listenfd;
        m_VariableC->conn_list[listenfd].r_action.accept_callback = accept_cb;
        set_event(listenfd, EPOLLIN, ADD);
    }

    m_VariableC->startPort = beginPort;
    m_VariableC->listenNumber = number;
#ifdef PRINTFCMODE
    printf("epoll fd:%d---startPort:%d---listenNumber:%d\n", m_VariableC->epfd, m_VariableC->startPort, m_VariableC->listenNumber);
    gettimeofday(&m_VariableC->begin, NULL);
#endif
}

void set_event(int fd, enum EPOLL_EVENTS events, enum _EPOLL_CTRL ctrl)
{
    struct epoll_event ev;
    ev.events = events;
    ev.data.fd = fd;
    epoll_ctl(m_VariableC->epfd, ctrl == ADD ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ev);
}

int accept_cb(int fd)
{
    struct sockaddr_in sockclient;
    socklen_t len = sizeof(sockclient);
    int clientfd = accept(fd, (struct sockaddr *)&sockclient, &len);
    set_event(clientfd, EPOLLIN, ADD);
#ifdef PRINTFCMODE
    printf("listen %d\tclientfd: %d\n", fd, clientfd);
#endif
    memset(m_VariableC->conn_list[clientfd].rbuffer, 0, sizeof(m_VariableC->conn_list[clientfd].rbuffer));
    m_VariableC->conn_list[clientfd].rlength = 0;
    memset(m_VariableC->conn_list[clientfd].wbuffer, 0, sizeof(m_VariableC->conn_list[clientfd].wbuffer));
    m_VariableC->conn_list[clientfd].wlength = 0;
    m_VariableC->conn_list[clientfd].fd = clientfd;
    m_VariableC->conn_list[clientfd].r_action.recv_callback = recv_cb;
    m_VariableC->conn_list[clientfd].send_callback = send_cb;

#ifdef PRINTFCMODE
    if (clientfd % 1000 == 0)
    {
        struct timeval current;
        gettimeofday(&current, NULL);
        int time_used = TIME_SUB_MS(current, m_VariableC->begin);
        memcpy(&m_VariableC->begin, &current, sizeof(struct timeval));
        printf("accept lientfd: %d\t time_used: %d\n", clientfd, time_used);
    }
#endif

    return clientfd;
}

int recv_cb(int fd)
{
    memset(m_VariableC->conn_list[fd].rbuffer,0,MAXBUFFERSIZE);
    m_VariableC->conn_list[fd].rlength = 0;

    int recvsize = recv(fd, m_VariableC->conn_list[fd].rbuffer, MAXBUFFERSIZE, 0);
    m_VariableC->conn_list[fd].rlength = recvsize;
    if (0 == recvsize)
    {
        close(fd);
        epoll_ctl(m_VariableC->epfd, EPOLL_CTL_DEL, fd, NULL);
#ifdef PRINTFCMODE
        printf("client disconnected:%d\n", fd);
#endif
        return 0;
    }
    else if (recvsize < 0) // 客户端发来reset信号，要正常处理
    {
#ifdef PRINTFCMODE
        printf("recvsize:%d,error:%d,%s\n", recvsize, errno, strerror(errno));
#endif
        close(fd);
        epoll_ctl(m_VariableC->epfd, EPOLL_CTL_DEL, fd, NULL);
        return 0;
    }
#ifdef PRINTFCMODE
    printf("client %d say: %s\n", fd, m_VariableC->conn_list[fd].rbuffer);
#endif

    if (parsercallback_Reactor != NULL)
    {
        parsercallback_Reactor(m_VariableC->conn_list[fd].rbuffer,m_VariableC->conn_list[fd].wbuffer);
        m_VariableC->conn_list[fd].wlength = strlen(m_VariableC->conn_list[fd].wbuffer);
    }
        
    set_event(fd, EPOLLOUT, MOD);

    return recvsize;
}

int send_cb(int fd)
{
    int sedsize = send(fd, m_VariableC->conn_list[fd].wbuffer, m_VariableC->conn_list[fd].wlength, 0);

#ifdef PRINTFCMODE
    printf("fd:%d say:%s,sedsize:%d\n",fd,m_VariableC->conn_list[fd].wbuffer,sedsize);
#endif

    memset(m_VariableC->conn_list[fd].wbuffer, 0, m_VariableC->conn_list[fd].wlength);
    m_VariableC->conn_list[fd].wlength = 0;
    set_event(fd, EPOLLIN, MOD);

    return 0;
}

void closeListen()
{
    for (int i = m_VariableC->startPort; i < m_VariableC->listenNumber; i++)
    {
        close(i);
    }
}

void NetworkStart_Reactor(pthread_t *tid)
{
    setListenPortNum(32767,MAX_PORTS);
    pthread_create(tid, NULL, runLoop_reactor, NULL);
}

void SetCallbackFun_Reactor(int (*CallbackParser)(char *Recvbuff,char *Sendbuff))
{
    parsercallback_Reactor = CallbackParser;
}

void setVariableC()
{
    m_VariableC = GetInstance();
}

void* runLoop_reactor(void *vrg)
{
    struct epoll_event evs[MAXBUFFERSIZE] = {0};
    while (1)
    {
#ifdef PRINTFCMODE
        printf("epoll_wait front---%d\n", m_VariableC->epfd);
#endif

        int readyfds = epoll_wait(m_VariableC->epfd, evs, MAXBUFFERSIZE, -1);

#ifdef PRINTFCMODE
        printf("readyfds:%d\n", readyfds);
#endif
        for (int i = 0; i < readyfds; i++)
        {
            int connfd = evs[i].data.fd;
            if (evs[i].events & EPOLLIN)
            {
                // 这里是知识盲区
                // 函数指针本质上是一个指向函数代码起始地址的指针。
                // 在联合体中，多个函数指针共享同一块内存，因此它们实际上指向的是同一个地址。
                // 这意味着，在联合体中，即使定义了多个函数指针，它们也只能同时指向一个函数
                m_VariableC->conn_list[connfd].r_action.accept_callback(connfd);
            }
            if (evs[i].events & EPOLLOUT)
            {
                m_VariableC->conn_list[connfd].send_callback(connfd);
            }
        }
    }

    closeListen();

    return NULL;
}